需求:文本超过10行时,需要支持折叠、收起。
要点:需要计算文本是否已经溢出
方案1:
使用GeometryReader
计算是否超过范围
方案2:
使用iOS16的ViewThatFits
伪代码:
swift
struct ExpandableTextView: View {
var text: String
@Binding var expaned: Bool
@Binding var isTruncated: Bool
init(text: String,
expaned: Binding<Bool>,
isTruncated: Binding<Bool>)
{
self.text = text
self._expaned = expaned
self._isTruncated = isTruncated
}
var body: some View {
if #available(iOS 16.0, *), false {
ParmaView(content: text)
.lineLimit(expaned ? nil : 10)
.frame(maxWidth: .infinity)
.background(
ViewThatFits(in: .vertical) {
ParmaView(content: text)
.hidden()
Color.clear // text doesn't fit
.onAppear {
isTruncated = true
}
}
)
} else {
ParmaView(content: self.text)
.frame(maxWidth: .infinity)
.lineLimit(self.expaned ? nil : 10)
.background(GeometryReader { geometry in
Color.clear.onAppear {
self.determineTruncation(geometry, text: self.text)
}
})
}
}
// https://stackoverflow.com/questions/59485532/swiftui-how-know-number-of-lines-in-text
private func determineTruncation(_ geometry: GeometryProxy, text: String) {
// Calculate the bounding box we'd need to render the
// text given the width from the GeometryReader.
let total = text.boundingRect(
with: CGSize(
width: geometry.size.width,
height: .greatestFiniteMagnitude
),
options: .usesLineFragmentOrigin,
attributes: [
.font: UIFont.systemFont(ofSize: 18),
],
context: nil
)
if total.size.height > geometry.size.height {
self.isTruncated = true
}
}
}
struct ExpandableTextView: View {
var text: String
@Binding var expaned: Bool
@Binding var isTruncated: Bool
init(text: String,
expaned: Binding<Bool>,
isTruncated: Binding<Bool>)
{
self.text = text
self._expaned = expaned
self._isTruncated = isTruncated
}
var body: some View {
if #available(iOS 16.0, *), false {
ParmaView(content: text)
.lineLimit(expaned ? nil : 10)
.frame(maxWidth: .infinity)
.background(
ViewThatFits(in: .vertical) {
ParmaView(content: text)
.hidden()
Color.clear // text doesn't fit
.onAppear {
isTruncated = true
}
}
)
} else {
ParmaView(content: self.text)
.frame(maxWidth: .infinity)
.lineLimit(self.expaned ? nil : 10)
.background(GeometryReader { geometry in
Color.clear.onAppear {
self.determineTruncation(geometry, text: self.text)
}
})
}
}
// https://stackoverflow.com/questions/59485532/swiftui-how-know-number-of-lines-in-text
private func determineTruncation(_ geometry: GeometryProxy, text: String) {
// Calculate the bounding box we'd need to render the
// text given the width from the GeometryReader.
let total = text.boundingRect(
with: CGSize(
width: geometry.size.width,
height: .greatestFiniteMagnitude
),
options: .usesLineFragmentOrigin,
attributes: [
.font: UIFont.systemFont(ofSize: 18),
],
context: nil
)
if total.size.height > geometry.size.height {
self.isTruncated = true
}
}
}